package com.trainfinder.ripper;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;
import org.w3c.tidy.Tidy;
import org.xml.sax.DTDHandler;
import org.xml.sax.InputSource;

import com.trainfinder.datapersistace.Journey;
import com.trainfinder.requestor.HtmlParser;
import com.trainfinder.requestor.IJourney;
import com.trainfinder.requestor.UnparsableException;

public class DomParser extends AbstractParser implements HtmlParser {

	public String tidy(String data) {
		Tidy tidy = new Tidy(); // obtain a new Tidy instance
		tidy.setXHTML(true);
		// tidy.setXmlOut(true);
		tidy.setQuiet(true);
		tidy.setShowWarnings(false);

		InputStream in = new ByteArrayInputStream(data.getBytes());
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		tidy.parse(in, out);

		data = new String(out.toByteArray());
		data = data.substring(data.indexOf("<html"), data.length());
		data = data.replaceAll("&copy;", "(c)");
		data = data.replaceAll("&nbsp;", " ");
		data = data.replaceAll("&pound;", "p");
		data = data.replaceAll("&amp;", "amp");
		data = data.replaceAll("&quot;", "quote");
		data = data.replaceAll("&lt;", "ltr");
		data = data.replaceAll("&gt;", "gtr");

		return data;
	}

	public List<IJourney> parseOutwardHTML(String data, String fromStation,
			String toStation, char outwardOrReturn, boolean awayOnSaturdayNight)
			throws UnparsableException {

		List<IJourney> result = new ArrayList<IJourney>();
		SAXBuilder saxBuilder = new SAXBuilder(
				"org.apache.xerces.parsers.SAXParser");
		final InputSource inputSource;
		final Document jdomDocument;
	final	InputStream inputStream = new ByteArrayInputStream(data
				.getBytes());
		try {

			saxBuilder.setValidation(false);
			saxBuilder.setIgnoringElementContentWhitespace(true);
			saxBuilder.setDTDHandler(null);
			 
			inputSource = new InputSource(inputStream);
			jdomDocument = saxBuilder.build(inputSource);

			Date date = getDate(jdomDocument);

			int rowCount = getRowCount(jdomDocument);
			int columnCount = getColumnCount(jdomDocument);

			Ticket[] tickets = getTickets(jdomDocument, columnCount);

			for (int row = 1; row <= rowCount; row++) {
				String rowPath = XPATH_STR + "[" + row + "]";
				Times times = getTimes(jdomDocument, rowPath);
				String[] prices = getPrices(jdomDocument, columnCount, rowPath);

				result.addAll(newJorneys(times, prices, date, tickets,
						fromStation, toStation, outwardOrReturn,
						awayOnSaturdayNight));
			}

		} catch (JDOMException e) {

			// e.printStackTrace();
			//
			// FileOutputStream outputStream;
			// try {
			// outputStream = new FileOutputStream(
			// "C:\\temp\\data.html");
			// outputStream.write(data.getBytes());
			// outputStream.close();
			// } catch (FileNotFoundException e1) {
			// // TODO Auto-generated catch block
			// e1.printStackTrace();
			// } catch (IOException e2) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
			e.printStackTrace();
			throw new UnparsableException(e);
		} catch (IOException e) {
			e.printStackTrace();
			throw new UnparsableException(e);
		}finally {
			try {
				inputStream.close();
			} catch (IOException e) {
				//
			}
		}
		return result;

	}

	private Collection<Journey> newJorneys(Times times, String[] prices,
			Date date, Ticket[] tickets, String fromStaion, String toStation,
			char outwardOrReturn, boolean awayOnSaturdayNight) {

		final Calendar calendar = Calendar.getInstance();
		final Collection<Journey> result = new ArrayList<Journey>();

		for (int i = 0; i < prices.length; i++) {

			if (tickets[i].getTicketClass() == TicketClass.Standard) {
				Journey journey = new Journey();
				journey.setFromStation(fromStaion);
				journey.setToStation(toStation);
				journey.setOutwardOrReturn(outwardOrReturn);
				journey.setDepartureHour(times.getDepartureHour());
				journey.setDepartureMin(times.getDepartureMin());
				journey.setArivalHour(times.getArivalHour());
				journey.setArivalMin(times.getArivalMin());
				journey.setDurationHour(times.getDurationHour());
				journey.setDurationMin(times.getDurationMin());

				if (awayOnSaturdayNight) {
					try {
						journey.setWeekendPence((int) (100 * Double
								.parseDouble(prices[i].substring(1))));
					} catch (NumberFormatException e) {
						journey.setWeekendPence(0);
					}
				} else {
					try {
						journey.setWeekdayPence((int) (100 * Double
								.parseDouble(prices[i].substring(1))));
					} catch (NumberFormatException e) {
						journey.setWeekdayPence(0);
					}
				}

				journey.id.setTicketType(tickets[i].getTicketType().ordinal());
				journey.id
						.setTicketClass(tickets[i].getTicketClass().ordinal());

				calendar.setTime(date);
				calendar.set(Calendar.HOUR_OF_DAY, times.getDepartureHour());
				calendar.set(Calendar.MINUTE, times.getDepartureMin());
				calendar.set(Calendar.SECOND, 0);
				journey.id.setDate(calendar.getTime());
				result.add(journey);
			}
		}
		return result;
	}

	private Times getTimes(Document jdomDocument, String rowPath)
			throws UnparsableException {

		String depatureXPath = rowPath + "/xhtml:td[1]";
		String departure = getTextFromNode(depatureXPath, jdomDocument);

		String arivalXPath = rowPath + "/xhtml:td[2]";
		String arival = getTextFromNode(arivalXPath, jdomDocument);

		String durationXPath = rowPath + "/xhtml:td[3]";
		String duration = getTextFromNode(durationXPath, jdomDocument);

		return new TimesImpl(departure, arival, duration);
	}

	private String[] getPrices(Document jdomDocument, int columnCount,
			String rowPath) throws UnparsableException {

		Collection<String> result = new ArrayList<String>();
		for (int column = 4; column <= columnCount; column++) {

			String depatureXPath = rowPath + "/xhtml:td[" + column
					+ "]/xhtml:label";

			String data = getTextFromNode(depatureXPath, jdomDocument);

			if (data == null) {
				result.add("SoldOut");
			} else {
				result.add(data);
			}
		}
		return (String[]) result.toArray(new String[result.size()]);

	}

	private Date getDate(Document jdomDocument) throws UnparsableException {
		Date result = null;
		final SimpleDateFormat dateFormat = new SimpleDateFormat(
				"EEEE d MMMM yyyy");

		String dateXPath = "/xhtml:html/xhtml:body/xhtml:div/"
				+ "xhtml:div[@id='center_01']/xhtml:form/"
				+ "xhtml:div[@id='calendar']/xhtml:h2/xhtml:strong";

		String date = getTextFromNode(dateXPath, jdomDocument);

		if (date == null) {
			throw new UnparsableException("unable to find the the date");
		}
		date = date.substring(0, date.length() - 1);

		int first = date.indexOf(" ");
		if (first == -1)
			throw new UnparsableException(
					"unable to find the first space in the date");

		int second = date.indexOf(" ", first + 1);
		if (second == -1)
			throw new UnparsableException(
					"unable to find the second space in the date");

		String number = date.substring(first, second);

		char chars[] = number.trim().toCharArray();

		StringBuffer numBuffer = new StringBuffer();
		for (int i = 0; i < chars.length; i++) {
			if (chars[i] >= '0' && chars[i] <= '9') {
				numBuffer.append(chars[i]);
			} else {
				break;
			}
		}

		date = date.substring(0, first + 1) + numBuffer.toString()
				+ date.substring(second, date.length());

		try {
			result = dateFormat.parse(date);
		} catch (ParseException e) {
			throw new UnparsableException(e);

		}
		return result;
	}

	public String getTextFromNode(String xPathStr, Document jdomDocument)
			throws UnparsableException {

		String result = "";

		try {
			Element e;
			XPath xp = XPath.newInstance(xPathStr);
			xp.addNamespace(NS);
			e = (Element) xp.selectSingleNode(jdomDocument);
			result = e.getText().trim();
		} catch (NullPointerException e) {
			return null;
		} catch (JDOMException e) {
			throw new UnparsableException(e);
		} catch (Exception e) {
			throw new UnparsableException(e);
		}

		return result;
	}

	public static void main(String[] args) throws IOException,
			UnparsableException {
		InputStream in;

		in = new FileInputStream(new File(
				"C:/Documents and Settings/Rob/Desktop/data-cp.html"));
		StringBuffer buff = new StringBuffer();
		int data;
		for (; (data = in.read()) != -1;) {
			buff.append((char) data);
		}

		new DomParser().parseOutwardHTML(buff.toString(), "london", "paris",
				'R', false);

	}
}
